-
Notifications
You must be signed in to change notification settings - Fork 188
Use PHP_CodeSniffer as a formatter #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Current coverage is 89.91% (diff: 91.48%)@@ master #35 diff @@
==========================================
Files 21 23 +2
Lines 456 496 +40
Methods 66 70 +4
Messages 0 0
Branches 0 0
==========================================
+ Hits 409 446 +37
- Misses 47 50 +3
Partials 0 0
|
felixfbecker
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM overall. Just some minor changes and more test coverage needed (see codecov)
src/Server/Formatter.php
Outdated
|
|
||
| use LanguageServer\Protocol\TextEdit; | ||
| use LanguageServer\Protocol\Range; | ||
| use LanguageServer\Protocol\Position; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use a group use statement here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/Server/Formatter.php
Outdated
| public function format(string $content, string $uri) | ||
| { | ||
| // remove 'file://' prefix | ||
| $uri = substr($uri, 7); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is the right way to do it - an input of file:///c:/users/felix/test would result in /c:/users/felix/test which is not a valid path. #31 adds a path2uri function, I would propose to add the reverse uri2path function (with some tests) https://github.com/MadHed/php-language-server/blob/7b0b9b890cabd3f0c2e1d7f10314ed61f53df110/src/utils.php#L23-L33
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now I added new method to Formatter to avoid conflicts with #31. Later I can move it to utils.php
src/Server/Formatter.php
Outdated
| $currentDir = dirname($currentDir); | ||
| } while ($currentDir !== '.' && $currentDir !== $lastDir); | ||
|
|
||
| $standard = \PHP_CodeSniffer::getConfigData('default_standard'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$standard = \PHP_CodeSniffer::getConfigData('default_standard') ?? 'PSR2'There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
I noticed that a big mess happens when formatting (in VSCode) the SymbolFinder.php file - in this part: https://github.com/felixfbecker/php-language-server/blob/master/src/SymbolFinder.php#L54-L63 |
|
Code Sniffer is failing to format SymbolFinder.php. I added simple error handling. Tomorrow I will report this problem to PHPCS. |
src/Server/Formatter.php
Outdated
| $file->fixer->fixFile(); | ||
| $fixed = $file->fixer->fixFile(); | ||
| if (!$fixed) { | ||
| throw new ResponseError("Unable to format file", ErrorCode::INTERNAL_ERROR); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use single quotes
|
I reported formatting issue: squizlabs/PHP_CodeSniffer#1180 |
|
Will merge #31 first, will probably be some refactoring for you to rebase |
|
Ok, I'm aware of that ;) |
|
Just merged #31 |
fb8848f to
0ba3304
Compare
src/Protocol/TextEdit.php
Outdated
| */ | ||
| public $newText; | ||
|
|
||
| public function __construct(Range $range = null, string $newText) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Non-optional parameter cannot follow an optional param. Both should be optional to allow constructing a instance and then setting the properties manually
tests/Utils/FileUriTest.php
Outdated
| $uri = "/home/foo/bar/Test.php"; | ||
| $this->assertEquals("/home/foo/bar/Test.php", \LanguageServer\uriToPath($uri)); | ||
|
|
||
| $uri = "/home/foo space/bar/Test.php"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a valid URI, space needs to be %20
tests/Utils/FileUriTest.php
Outdated
| $uri = "file:///c:/home/foo/bar/Test.php"; | ||
| $this->assertEquals("c:\\home\\foo\\bar\\Test.php", \LanguageServer\uriToPath($uri)); | ||
|
|
||
| $uri = "c:\\home\\foo\\bar\\Test.php"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not a valid URI so I don't think we need to test against it
src/utils.php
Outdated
| return $uri; | ||
| } | ||
| $path = substr($uri, $position + 3); | ||
| return strpos($path, ':') ? str_replace('/', "\\", substr($path, 1)) : $path; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not that happy with this implementation.
- If possible I would like to use
parse_url - Needs to handle %-encoding
- Needs to replace
/withDIRECTORY_SEPERATOR
tests/Server/TextDocumentTest.php
Outdated
| $textDocument = new Server\TextDocument($project, $client); | ||
|
|
||
| $result = $textDocument->formatting(new TextDocumentIdentifier('whatever'), new FormattingOptions()); | ||
| $this->assertEquals([], json_decode(json_encode($result), true)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Imo an invalid URI should throw an error instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actual implementation will create PhpDocument for invalid/non-existing uri (Project::getDocument). I can try to reorganize this with this change but I think it should be done as separate issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough.
src/Formatter.php
Outdated
| do { | ||
| $default = $currentDir . DIRECTORY_SEPARATOR . 'phpcs.xml'; | ||
| if (is_file($default) === true) { | ||
| return array($default); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use short array syntax
felixfbecker
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests for uriToPath and pathToUri should be symmetric, could you clean them up a bit?
src/utils.php
Outdated
| $path = substr($uri, $position + 3); | ||
| return strpos($path, ':') ? str_replace('/', "\\", substr($path, 1)) : $path; | ||
| $path = urldecode(parse_url($uri)['path']); | ||
| return strpos($path, ':') ? str_replace(\DIRECTORY_SEPARATOR, '\\', substr($path, 1)) : $path; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strposmay return0orfalse, should check explicitly forfalsehere- It's
str_replace($search, $replace, $subject), we need to search for'/'and replace it withDIRECTORY_SEPERATOR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be ok right now.
tests/Utils/FileUriTest.php
Outdated
| $uri = 'file:///a/b/c/test.txt'; | ||
| $this->assertEquals('/a/b/c/test.txt', \LanguageServer\uriToPath($uri)); | ||
| $uri = 'file:///c%3A/foo/bar.baz'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The colon after the drive letter is typically not encoded afaik
https://en.wikipedia.org/wiki/File_URI_scheme#Windows_2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to simple colon.
src/Formatter.php
Outdated
| if ($content === $new) { | ||
| return []; | ||
| } | ||
| return [new TextEdit(new Range(new Position(0, 0), new Position(PHP_INT_MAX, PHP_INT_MAX)), $new)]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eclipse Che requires an accurate calculation of the end position. Although VSCode can handle this well, the editor in Che just breaks if any negative values or big values beyond the document end are provided.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I will try to calculate end position.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! This now works very well in Che.
|
@felixfbecker is there anything else pending (except resolving conflicts) for this PR to be merged? |
felixfbecker
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There a few minor nitpicks which I will just fix myself if you don't beat me to it. The important stuff really is support for non-file URIs
src/Formatter.php
Outdated
| { | ||
| $path = uriToPath($uri); | ||
| $cs = new \PHP_CodeSniffer(); | ||
| $cs->initStandard($this->findConfiguration($path)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this also work in environments where
- URIs are not file URIs
- there is no config file in the project
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this also work in environments where
URIs are not file URIs
For directory URI it wont work if URI = directory with config file but in this case it will load default configuration. Should we be worried about such cases? Do you notices URIs different than file?
there is no config file in the project ?
If config file is not found PSR2 standard is loaded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I meant was that we need to handle URIs that don't use the file:// scheme, but something like vfs://.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, understand now. We can think about it later.
src/utils.php
Outdated
| */ | ||
| function uriToPath(string $uri) | ||
| { | ||
| $filepath = urldecode(parse_url($uri)['path']); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A URI can have any protocol, but only file URIs can be mapped to a path. We need to throw an InvalidArgumentException if the URI is not a file:// URI and also handle/test that case in the implementation.
| function uriToPath(string $uri) | ||
| { | ||
| $filepath = urldecode(parse_url($uri)['path']); | ||
| return strpos($filepath, ':') === false ? $filepath : str_replace('/', '\\', $filepath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a little brittle. There are also implementations that use | instead of the colon on windows. You don't need to test against that, but it would be better to simply do str_replace('/', DIRECTORY_SEPERATOR, $filepath)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forget what I said. the directory separator should of course be determined by the URI, not the runtime OS.
src/Formatter.php
Outdated
| private function calculateEndPosition(string $content): Position | ||
| { | ||
| $lines = explode("\n", $content); | ||
| return new Position(sizeof($lines) - 1, strlen(end($lines))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use count, sizeof is just an alias and PHP has so many aliases nobody can remember them all 😄
src/Formatter.php
Outdated
| * @param string $uri | ||
| * @return string[] | ||
| */ | ||
| private function findConfiguration(string $uri) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter is named $uri, but you call it with a path, not a URI. Some description for the function and params would also be nice
tests/FormatterTest.php
Outdated
| $this->assertTrue($edits == []); | ||
| } | ||
|
|
||
| } No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing newline - I don't know which editor you use but I recommend you to look for an EditorConfig extension 😉
src/Formatter.php
Outdated
| use LanguageServer\Protocol\{TextEdit, Range, Position, ErrorCode}; | ||
| use AdvancedJsonRpc\ResponseError; | ||
|
|
||
| class Formatter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initially I was wondering why this needs to be a class that is instantiated when it has no properties, constructor or internal state. Everything could just be pure functions. But it's probably better to encapsulate the private functions. One possibility would be though to make them static and the class abstract. Opinions on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this class to prevent messing with PhpDocument in future. Abstract class and static methods sounds ok for me.
tests/Server/TextDocumentTest.php
Outdated
| $textDocument = new Server\TextDocument($project, $client); | ||
|
|
||
| $result = $textDocument->formatting(new TextDocumentIdentifier('whatever'), new FormattingOptions()); | ||
| $this->assertEquals([], json_decode(json_encode($result), true)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough.
tests/Server/TextDocumentTest.php
Outdated
| $textDocument = new Server\TextDocument($project, $client); | ||
|
|
||
| $result = $textDocument->formatting(new TextDocumentIdentifier('whatever'), new FormattingOptions()); | ||
| $this->assertEquals([], json_decode(json_encode($result), true)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need to json_decode(json_encode())
src/Formatter.php
Outdated
| public function format(string $content, string $uri) | ||
| { | ||
| $path = uriToPath($uri); | ||
| $cs = new \PHP_CodeSniffer(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a use PHP_CodeSniffer at the top. This declares the dependency on the class and avoids having to use absolute references
|
Fixed the style issues |
|
I think this is good to go, just needs a rebase |
1642754 to
47482fc
Compare
No description provided.